
#include <stdio.h>
#include <stdint.h>


uint8_t v6_data[] = {
      0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x21, 0x43, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x11, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00
};

uint8_t v4_data[] = {
      0x48, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x85, 0x60, 0x0e, 0xaf, 0xf2, 0x84
    , 0x0a, 0x21, 0x55, 0x02, 0x94, 0x04, 0x00, 0x00, 0x89, 0x04, 0x00, 0x00, 0x00, 0x1a, 0xbf, 0xb5
};


enum
  {
    IPPROTO_IP = 0,	   /* Dummy protocol for TCP.  */
#define IPPROTO_IP		IPPROTO_IP
    IPPROTO_ICMP = 1,	   /* Internet Control Message Protocol.  */
#define IPPROTO_ICMP		IPPROTO_ICMP
    IPPROTO_IGMP = 2,	   /* Internet Group Management Protocol. */
#define IPPROTO_IGMP		IPPROTO_IGMP
    IPPROTO_IPIP = 4,	   /* IPIP tunnels (older KA9Q tunnels use 94).  */
#define IPPROTO_IPIP		IPPROTO_IPIP
    IPPROTO_TCP = 6,	   /* Transmission Control Protocol.  */
#define IPPROTO_TCP		IPPROTO_TCP
    IPPROTO_EGP = 8,	   /* Exterior Gateway Protocol.  */
#define IPPROTO_EGP		IPPROTO_EGP
    IPPROTO_PUP = 12,	   /* PUP protocol.  */
#define IPPROTO_PUP		IPPROTO_PUP
    IPPROTO_UDP = 17,	   /* User Datagram Protocol.  */
#define IPPROTO_UDP		IPPROTO_UDP
    IPPROTO_IDP = 22,	   /* XNS IDP protocol.  */
#define IPPROTO_IDP		IPPROTO_IDP
    IPPROTO_TP = 29,	   /* SO Transport Protocol Class 4.  */
#define IPPROTO_TP		IPPROTO_TP
    IPPROTO_DCCP = 33,	   /* Datagram Congestion Control Protocol.  */
#define IPPROTO_DCCP		IPPROTO_DCCP
    IPPROTO_IPV6 = 41,     /* IPv6 header.  */
#define IPPROTO_IPV6		IPPROTO_IPV6
    IPPROTO_RSVP = 46,	   /* Reservation Protocol.  */
#define IPPROTO_RSVP		IPPROTO_RSVP
    IPPROTO_GRE = 47,	   /* General Routing Encapsulation.  */
#define IPPROTO_GRE		IPPROTO_GRE
    IPPROTO_ESP = 50,      /* encapsulating security payload.  */
#define IPPROTO_ESP		IPPROTO_ESP
    IPPROTO_AH = 51,       /* authentication header.  */
#define IPPROTO_AH		IPPROTO_AH
    IPPROTO_MTP = 92,	   /* Multicast Transport Protocol.  */
#define IPPROTO_MTP		IPPROTO_MTP
    IPPROTO_BEETPH = 94,   /* IP option pseudo header for BEET.  */
#define IPPROTO_BEETPH		IPPROTO_BEETPH
    IPPROTO_ENCAP = 98,	   /* Encapsulation Header.  */
#define IPPROTO_ENCAP		IPPROTO_ENCAP
    IPPROTO_PIM = 103,	   /* Protocol Independent Multicast.  */
#define IPPROTO_PIM		IPPROTO_PIM
    IPPROTO_COMP = 108,	   /* Compression Header Protocol.  */
#define IPPROTO_COMP		IPPROTO_COMP
    IPPROTO_SCTP = 132,	   /* Stream Control Transmission Protocol.  */
#define IPPROTO_SCTP		IPPROTO_SCTP
    IPPROTO_UDPLITE = 136, /* UDP-Lite protocol.  */
#define IPPROTO_UDPLITE		IPPROTO_UDPLITE
    IPPROTO_MPLS = 137,    /* MPLS in IP.  */
#define IPPROTO_MPLS		IPPROTO_MPLS
    IPPROTO_RAW = 255,	   /* Raw IP packets.  */
#define IPPROTO_RAW		IPPROTO_RAW
    IPPROTO_MAX
  };

#if !__USE_KERNEL_IPV6_DEFS
enum
  {
    IPPROTO_HOPOPTS = 0,   /* IPv6 Hop-by-Hop options.  */
#define IPPROTO_HOPOPTS		IPPROTO_HOPOPTS
    IPPROTO_ROUTING = 43,  /* IPv6 routing header.  */
#define IPPROTO_ROUTING		IPPROTO_ROUTING
    IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header.  */
#define IPPROTO_FRAGMENT	IPPROTO_FRAGMENT
    IPPROTO_ICMPV6 = 58,   /* ICMPv6.  */
#define IPPROTO_ICMPV6		IPPROTO_ICMPV6
    IPPROTO_NONE = 59,     /* IPv6 no next header.  */
#define IPPROTO_NONE		IPPROTO_NONE
    IPPROTO_DSTOPTS = 60,  /* IPv6 destination options.  */
#define IPPROTO_DSTOPTS		IPPROTO_DSTOPTS
    IPPROTO_MH = 135       /* IPv6 mobility header.  */
#define IPPROTO_MH		IPPROTO_MH
  };
#endif /* !__USE_KERNEL_IPV6_DEFS */


#define RTE_IPV6_FRAG_HDR_SIZE          8

static inline int
advrule_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len, int *is_ra)
{
	int next_proto;

	switch (proto) {
	case IPPROTO_AH:
		next_proto = *p++;
		*ext_len = (*p + 2) * sizeof(uint32_t);
		break;

	case IPPROTO_HOPOPTS:
	case IPPROTO_ROUTING:
	case IPPROTO_DSTOPTS:
		next_proto = *p++;
        *ext_len = (*p++ + 1) * sizeof(uint64_t);

        size_t len = 0, type;
        while(len + 2 < *ext_len)
        {
            type = *p++;
            if(5 == type)
            {
                *is_ra = 1;  
                break;
            }
            else if(0 == type)
            {
                break;
            }   
            len += 2;         
            len += *p++;
        }		
		break;

	case IPPROTO_FRAGMENT:
		next_proto = *p;
		*ext_len = RTE_IPV6_FRAG_HDR_SIZE;
		break;

	default:
		return -1;
	}

	return next_proto;
}

/**
 * IPv6 Header
 */
struct rte_ipv6_hdr {
	uint32_t vtc_flow;	/**< IP version, traffic class & flow label. */
	uint16_t payload_len;	/**< IP packet length - includes header size */
	uint8_t  proto;		/**< Protocol, next header. */
	uint8_t  hop_limits;	/**< Hop limits. */
	uint8_t  src_addr[16];	/**< IP address of source host. */
	uint8_t  dst_addr[16];	/**< IP address of destination host(s). */
} __rte_packed;



int ipv6_opt_parse()
{
    size_t ext_len;
    int l3len, next_proto, is_ra = 0;
    struct rte_ipv6_hdr *ip_hdr = v6_data;

    l3len = sizeof(struct rte_ipv6_hdr);
    next_proto = ip_hdr->proto;
    while (next_proto != IPPROTO_ESP && l3len < ip_hdr->payload_len)
    {
        next_proto = advrule_ipv6_get_next_ext(((uint8_t *)ip_hdr) + l3len, next_proto, &ext_len, &is_ra);
        if(next_proto < 0)break;
        l3len += ext_len;
        printf("%d %d \n", ext_len, next_proto);
    }
  
    printf("%d \n", is_ra);
   

    return 0;
}



struct rte_ipv4_hdr {
	uint8_t  version_ihl;		/**< version and header length */
	uint8_t  type_of_service;	/**< type of service */
	uint16_t total_length;	/**< length of packet */
	uint16_t packet_id;		/**< packet ID */
	uint16_t fragment_offset;	/**< fragmentation offset */
	uint8_t  time_to_live;		/**< time to live */
	uint8_t  next_proto_id;		/**< protocol ID */
	uint16_t hdr_checksum;	/**< header checksum */
	uint32_t src_addr;		/**< source address */
	uint32_t dst_addr;		/**< destination address */
} ;


int ipv4_opt_parse()
{
    int hdr_len = (*(uint8_t *)v4_data & 0xf) << 2;
    if(hdr_len == sizeof(struct rte_ipv4_hdr))  // 没有选项信息
    {
        return -1;
    }
    
    // 选项信息解析            
    uint8_t *ipv4_opt;
    uint8_t opt_type[256] = {0};
    int len = sizeof(struct rte_ipv4_hdr);
    while((len + 2) < hdr_len)
    {
        uint8_t *ipv4_opt = len + (uint8_t *)v4_data;
        opt_type[*ipv4_opt] = 1;
        if(! *(ipv4_opt+1))break;
        len += *(ipv4_opt+1);
    }

    for(int i=0; i<256; i++)
    {
        if(!opt_type[i])continue;
        printf("%d %d \n", i, opt_type[i]);
    }
    return 0;
}


int main()
{
    ipv4_opt_parse();

    return 0;
}